import { ref, onUnmounted } from "vue";

import { Map, View, Feature } from "ol";

import type { MapOptions } from "ol/Map";

import { LineString, Point } from "ol/geom";

import { Style, Text, Icon, Stroke, Fill } from "ol/style";

import { Tile as TileLayer, Vector as VectorLayer } from "ol/layer";

import { Vector as VectorSource, XYZ as TileXYZ, TileWMS } from "ol/source";

import "ol/ol.css";

export interface ViewConfig {
  center?: [number, number];
  projection?: string;
  zoom?: number;
  maxZoom?: number;
  minZoom?: number;
}
export interface initConfig {
  view: ViewConfig;
}

/**
 *  使用封装的OpenLayers方法
 * @param target 地图容器id
 * @param handleClick 地图点击事件的回调，参数为点中的features
 * @returns
 */
export const useOpenLayers = (target: string, handleClick?: Function) => {
  const map = ref();

  // 销毁地图
  onUnmounted(() => map.value.dispose());

  const getLonLat = (obj: any) =>
    [obj.lon || obj.longitude, obj.lat || obj.latitude].map(Number) as [
      number,
      number
    ];

  const getCenterByExtent = ([x0, y0, x1, y1]: number[]) => {
    const x = x0 + (x1 - x0) / 2;
    const y = y0 + (y1 - y0) / 2;
    return [x, y];
  };

  /**
   *  初始化地图
   * @param option：{ view:视角配置 }
   */
  const initMap = (option: initConfig) => {
    map.value = new Map({
      target,
      view: new View({
        projection: "EPSG:4326",
        center: [120.209761, 30.211145], //自己设置中心点，也可以不设置
        zoom: 10,
        maxZoom: 18,
        minZoom: 5,
        ...option.view,
      }),
      controls: [], //控件
    });

    // 鼠标划过feature变成小手
    map.value.on("pointermove", (evt: any) => {
      const pixel = map.value.getEventPixel(evt.originalEvent);
      const hit = map.value.hasFeatureAtPixel(pixel);
      map.value.getTargetElement().style.cursor = hit ? "pointer" : "";
    });

    map.value.on("click", (e: any) => {
      if (!handleClick) return;
      const features = map.value.getFeaturesAtPixel(e.pixel);
      // console.log(features);
      handleClick(features, e);
    });
  };

  /**
   *  添加天地图
   * @param tk 天地图key
   * @param opacity 设置透明度，默认为1
   */
  const addTiandiLayer = (tk: string, opacity = 1) => {
    // 后续将tk从环境变量中读取
    const layer = new TileLayer({
      className: "tilelayer",
      source: new TileXYZ({
        url: `http://t{0-7}.tianditu.com/DataServer?x={x}&y={y}&l={z}&T=vec_c&tk=${tk}`,
        projection: "EPSG:4326",
      }),
      opacity,
    });
    map.value.addLayer(layer);
  };

  /**
   * 移除图层
   * @param name 图层名称(可选)
   */
  const removeLayer = (name?: string) => {
    const getAllLayers = map.value.getLayers().getArray();

    for (let i = 0, len = getAllLayers.length; i < len; i++) {
      const layer = getAllLayers[i];

      if (!name || layer.className_ === name) map.value.removeLayer(layer);
    }
  };

  /**
   * 添加点位
   * @param list 点位信息数组
   * @param type 点位类型标志
   */
  const addMakers = (list: any[], type: string) => {
    //清除已存在的相同类型的点位图层
    removeLayer(type);

    const overFeature = [];

    for (let i = 0, len = list.length; i < len; i++) {
      const current = list[i];

      const featureItem = new Feature({
        geometry: new Point(getLonLat(current)),
        // 覆盖物额外属性
        // id: type,
        type,
        name: current.name,
        data: current,
      });
      featureItem.setStyle(
        new Style({
          image: new Icon({
            src: "/src/assets/icons/maker.svg",
            // imgSize: [50, 50],
            scale: 1,
          }),
          text: new Text({
            text: current.name,
            font: `normal  14px 微软雅黑`, //文字样式
            offsetY: 35,
            padding: [5, 12, 2, 12],
            // rotateWithView: true,
            fill: new Fill({
              color: "#ffffff",
            }),
            backgroundFill: new Fill({
              // 背景色
              color: "rgba( 36, 60, 140 , 0.8)",
            }),
            backgroundStroke: new Stroke({
              // 边框,
              color: "#034ea1",
            }),
          }),
        })
      );
      overFeature.push(featureItem);
    }

    map.value.addLayer(
      new VectorLayer({
        className: type,
        source: new VectorSource({
          features: overFeature,
        }),
      })
    );
  };

  /**
   * 设置地图视角中心
   * @param center [经度,纬度]
   * @param duration 视角移动动画时长（默认300毫秒）
   */
  const setView = (center: [number, number], duration = 300) => {
    map.value.getView().animate({
      center,
      // zoom,
      duration,
    });
  };

  /**
   * 设置地图视角中心
   * @param obj 包含经纬度信息的对象
   * @param duration 视角移动动画时长（默认300毫秒）
   */
  const setViewByObj = (obj: any, duration = 300) => {
    const center = getLonLat(obj);
    setView(center, duration);
  };

  /**
   *  添加断裂带
   * @param fractureData 断裂带数据
   */
  const addFracture = (fractureData: any[]) => {
    // 数据筛选
    const getRange = (e: any) => {
      const [lon, lat] = e.geometry.coordinates[0][0];
      const verifyLon = lon > 120 && lon < 130;
      const verifyLat = parseInt(lat) === 30;
      return verifyLon && verifyLat;
    };
    fractureData = fractureData.filter(getRange);
    // console.log(fractureData);

    const features: any[] = [];
    for (let i = 0, len = fractureData.length; i < len; i++) {
      const item = fractureData[i];
      const lineFeature = new Feature({
        id: "断裂带",
        geometry: new LineString(item.geometry.coordinates[0]),
      });
      lineFeature.setStyle(
        new Style({
          stroke: new Stroke({
            color: "#fd8b2b",
            width: 5,
          }),
          text: new Text({
            placement: "line",
            font: "16px sans-serif",
            text: "断裂带" + i + 1,
            // text: item.properties.name === "无" ? "" : item.properties.name,
            textBaseline: "middle",
            overflow: false, // 文本超出几何体最大宽度后溢出部分隐藏
            stroke: new Stroke({
              color: "#fff",
              width: 2,
            }),
          }),
        })
      );
      features.push(lineFeature);
    }
    map.value.addLayer(
      new VectorLayer({
        className: "断裂带",
        source: new VectorSource({
          features: features,
        }),
      })
    );
  };

  return {
    initMap,
    addTiandiLayer,
    addMakers,
    setView,
    setViewByObj,
    removeLayer,
    addFracture,
  };
};
